import { HttpException, HttpStatus, Inject, Injectable } from '@nestjs/common';
import {
  User,
  UpdateUserDto,
  createUserDto
} from 'libs/db/src/schemas/user.schemas';
import { QueryUserDto } from './dto/queryUserDto';
import { ReturnModelType } from '@typegoose/typegoose';

@Injectable()
export class UserService {
  constructor(
    @Inject(User.name)
    private readonly userModel: ReturnModelType<typeof User>
  ) {}

  /**
   * 异步注册新用户函数
   * @param createUserDto 参数，创建用户Dto
   * @returns
   */
  // async regist(createUserDto: createUserDto) {
  //   // 在数据库中查找用户名是否已存在
  //   return (
  //     this.userModel
  //       .findOne({
  //         username: createUserDto.username
  //       })
  //       .then((res) => {
  //         // 如果用户名已存在，抛出错误
  //         if (res) {
  //           throw new Error('用户名已存在');
  //         }
  //       })
  //       // 如果用户名不存在，创建新用户
  //       .then(() => {
  //         try {
  //           return this.userModel.create(createUserDto);
  //         } catch (err) {
  //           // 如果创建用户失败，抛出错误
  //           throw new Error('保存用户失败' + err);
  //         }
  //       })
  //       // 捕获错误，并抛出HttpException
  //       .catch((err) => {
  //         console.warn('发生问题--' + err);
  //         throw new HttpException(
  //           `注册新用户${createUserDto.username}失败！${err}`,
  //           HttpStatus.FORBIDDEN
  //         );
  //       })
  //   );
  // }

  /**
   * 创建用户
   * @param createUserDto 参数，创建用户Dto
   * @returns
   */
  async create(createUserDto: createUserDto) {
    try {
      const exist = await this.existUser(createUserDto.username);
      if (exist) {
        throw new HttpException(
          '用户账号已存在，创建失败！',
          HttpStatus.FORBIDDEN
        );
      }
      return this.userModel.create(createUserDto);
    } catch (err) {
      throw err;
    }
  }

  /**
   * 查找所有用户
   * @returns
   */
  async findAll() {
    // 查找所有用户，并排除__v字段
    return this.userModel.find();
  }

  /**
   * 根据查询参数分页查询用户
   * @param dto 查询参数
   * @returns
   */
  async pageQuery(dto: QueryUserDto) {
    const { limit, page, username, realname, mobile, status, createAt } = dto;

    const query = {} as any;
    if (username) {
      query.username = { $regex: username, $options: 'i' };
    }
    if (realname) {
      query.realname = { $regex: realname, $options: 'i' };
    }

    if (mobile) {
      query.mobile = { $regex: mobile, $options: 'i' };
    }
    if (createAt) {
      query.createdAt = {
        $gte: new Date(createAt[0]),
        $lt: new Date(createAt[1])
      };
    }
    if (status) {
      query.status = true;
    } else if (status === false) {
      query.status = false;
    }
    // console.log(query);

    const total = await this.userModel.aggregate([
      {
        $match: query
      },
      {
        $count: 'total'
      }
    ]);

    const list = await this.userModel.aggregate([
      {
        $match: query
      },
      {
        $sort: {
          createdAt: -1
        }
      },
      {
        $skip: (page - 1) * limit
      },
      {
        $limit: limit
      }
    ]);

    return {
      total: total[0]?.total || 0,
      list
    };
  }

  /**
   * 判断用户名是否存在
   * @param username 参数，用户名
   * @returns
   */
  async existUser(username: string) {
    // 查找用户名是否已存在
    const exist = await this.userModel.findOne({ username });
    // 返回是否存在
    return !!exist;
  }

  /**
   * auth页面中要根据用户名查询用户信息，其中密码和盐值需要验证，不能排除
   * @param username 参数，用户名
   * @returns
   */
  async findByUsername(username: string) {
    return this.userModel.findOne({ username });
  }

  async findByUserId(userId: string) {
    return this.userModel.findOne({ userId });
  }

  async findById(id: string) {
    return this.userModel.findById(id).select({ password: 0, salt: 0 }).exec();
  }

  // async函数用于定义异步函数，返回一个Promise对象
  async update(id: string, updateUserDto: UpdateUserDto) {
    // 使用findByIdAndUpdate方法更新指定id的用户信息，返回更新后的用户信息
    return this.userModel.findByIdAndUpdate(id, updateUserDto, {
      new: true
    });
  }

  async remove(id: string) {
    return this.userModel.findByIdAndDelete(id);
  }
}
